package com.vpen.iot.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import com.google.protobuf.ByteString;
import com.vpen.iot.client.IotClient;
import com.vpen.iot.manager.ExportThreadPool;
import com.vpen.iot.manager.LinkInfo;
import com.vpen.iot.manager.LinkManager;
import com.vpen.iot.model.dto.TestAppDto;
import com.vpen.iot.server.message.Packet;
import com.vpen.iot.server.message.User;
import com.vpen.iot.server.message.v2.JT808Message;
import com.vpen.iot.server.message.v2.Message;
import com.vpen.iot.utils.BCDUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Vpen
 * @date 2023/7/8 11:53
 */
@Slf4j
@RequestMapping("/api")
@RestController
public class SendController {

    @GetMapping(value = "/connect")
    public void get() {

        LinkInfo linkInfo = LinkManager.getLinkInfo("key");
        Channel channel = linkInfo.getChannel();
        if (Objects.isNull(channel)) {
            channel = IotClient.connect("192.168.20.72", 9999);
            LinkManager.addChannel("key", channel);
        } else {
            channel = linkInfo.getChannel();
        }

        User.UserBase.Builder userPr = User.UserBase.newBuilder();

        User.Header.Builder header = User.Header.newBuilder();
        header.setMsgId(1);
        header.setMsgLen(51);
        header.setTimestamp(System.currentTimeMillis());

        User.Body.Builder body = User.Body.newBuilder();
        User.ClassInfo.Builder classInfo = User.ClassInfo.newBuilder();
        classInfo.setGrade(1);
        classInfo.setNumber(123);
        body.setClassInfo(classInfo);
        userPr.setHeader(header);
        userPr.setBody(body);
        channel.writeAndFlush(userPr);

        System.out.println(channel);
    }

    @GetMapping(value = "/808")
    public void get2() {

        LinkInfo linkInfo = LinkManager.getLinkInfo("key");
        Channel channel = linkInfo.getChannel();
        if (Objects.isNull(channel)) {
            channel = IotClient.connect("192.168.20.72", 9999);
            LinkManager.addChannel("key", channel);
        } else {
            channel = linkInfo.getChannel();
        }

        Packet.PacketBase.Builder packetBase = Packet.PacketBase.newBuilder();

        // 消息头
        Packet.Header808.Builder header = Packet.Header808.newBuilder();
        header.setMsgId(0x0200);
        header.setAttribute(1);
        header.setSerialNo(1);
        // 手机号使用BCD编码
        header.setSimNoBytes(ByteString.copyFrom(BCDUtil.str2Bcd("13457115048")));
        Packet.HeaderBase.Builder headerBase = Packet.HeaderBase.newBuilder();
        headerBase.setHeader808(header);

        // 消息体
        Packet.BodyBase.Builder bodyBase = Packet.BodyBase.newBuilder();
        Packet.Body808.Builder body808 = Packet.Body808.newBuilder();
        body808.setMsg("hello,world");
        bodyBase.setBody808(body808);


        packetBase.setHeader(headerBase);
        packetBase.setBody(bodyBase);
        channel.writeAndFlush(packetBase);

        System.out.println(channel);
    }

    @GetMapping(value = "/v2/808")
    public void get3() {

        LinkInfo linkInfo = LinkManager.getLinkInfo("key");
        Channel channel = linkInfo.getChannel();
        if (Objects.isNull(channel)) {
            channel = IotClient.connect("192.168.20.72", 9999);
            LinkManager.addChannel("key", channel);
        } else {
            channel = linkInfo.getChannel();
        }

        Message.MessageBase.Builder builder = Message.MessageBase.newBuilder();

        JT808Message.JT808MessageProto.Builder jt808 = JT808Message.JT808MessageProto.newBuilder();
        jt808.setMsgId(0x0200);
        jt808.setMsgAttr(1);
        jt808.setPhoneNo("13457115048");
        jt808.setFlowId(1);
        builder.setMsg808(jt808);

        channel.writeAndFlush(jt808);


        System.out.println(channel);
    }

    @PostMapping(value = "/v2/test")
    public void test(@RequestBody TestAppDto dto) {
        ExportThreadPool pool = ExportThreadPool.getInstance();
        pool.submit(() -> {
            try {
                Thread.sleep(5000);
                log.debug("我在执行任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        BlockingQueue<Runnable> queue = pool.getQueue();
        System.out.println(queue.size());
        log.debug("我熬");
    }


//    @GetMapping("/download-excel")
//    public ResponseEntity<StreamingResponseBody> downloadExcel() {
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentDispositionFormData("attachment", "data.xlsx");
//        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//
//        StreamingResponseBody stream = outputStream -> {
//            try (Workbook workbook = new XSSFWorkbook()) {
//                Sheet sheet = workbook.createSheet("Data");
//
//                // 模拟从数据库查询大数据集
//                List<String[]> data = fetchLargeDataset();
//
//                int rowIndex = 0;
//                for (String[] rowData : data) {
//                    Row row = sheet.createRow(rowIndex++);
//                    for (int i = 0; i < rowData.length; i++) {
//                        row.createCell(i).setCellValue(rowData[i]);
//                    }
//
//                    if (rowIndex % 1 == 0) {
//                        try {
//                            Thread.sleep(500);
//                            log.debug("业务耗时。。。。");
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        workbook.write(outputStream);
//                        outputStream.flush();
//                    }
//                }
//
//                workbook.write(outputStream);
//            }
//        };
//
//        return new ResponseEntity<>(stream, headers, HttpStatus.OK);
//    }
//
//    private List<String[]> fetchLargeDataset() {
//        // 模拟从数据库查询数据
//        // 实际场景中你可以通过分页查询数据并返回列表
//        return Arrays.asList(
//                new String[]{"Header1", "Header2", "Header3"},
//                new String[]{"Row1Col1", "Row1Col2", "Row1Col3"},
//                new String[]{"Row2Col1", "Row2Col2", "Row2Col3"},
//                new String[]{"Row2Col2", "Row2Col3", "Row2Col3"},
//                new String[]{"Row2Col3", "Row2Col3", "Row2Col3"},
//                new String[]{"Row2Col4", "Row2Col3", "Row2Col3"},
//                new String[]{"Row2Col5", "Row2Col3", "Row2Col3"}
//                // 添加更多数据行
//        );
//    }

    @GetMapping("/download-excel")
    public ResponseEntity<StreamingResponseBody> downloadExcel() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "data.xlsx");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        StreamingResponseBody stream = outputStream -> {
            ExportParams exportParams = new ExportParams("Data Export", "Sheet1", ExcelType.XSSF);

            // 初始化 Workbook
//            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, TestAppDto.class, new ArrayList<>());
            MySXSSFWorkbook workbook = new MySXSSFWorkbook();


            // 获取 Sheet
            Sheet sheet = workbook.createSheet();

            // 模拟分页查询数据并逐步写入
            List<TestAppDto> dataBatch;
            int pageIndex = 0;
            boolean hasNextPage = true;
            while (hasNextPage) {
                dataBatch = fetchDataByPage(pageIndex);

                // 从第二行开始追加数据（跳过标题行）
                int rowStart = sheet.getPhysicalNumberOfRows() + 1;
                log.debug("rowStart:{}", rowStart);
                for (int i = 0; i < dataBatch.size(); i++) {
                    Row row = sheet.createRow(rowStart + i);
                    TestAppDto data = dataBatch.get(i);
                    row.createCell(0).setCellValue(data.getStr());
                    row.createCell(1).setCellValue(data.getSuccess());
                }


                // 刷新输出流，将数据写出
                workbook.write(outputStream);
                outputStream.flush();


                hasNextPage = !dataBatch.isEmpty();
                pageIndex++;
            }
//            workbook.write(outputStream);
//            outputStream.flush();

            workbook.close();
        };

        return new ResponseEntity<>(stream, headers, HttpStatus.OK);
    }


    @GetMapping("/download-excel-2")
    public ResponseEntity<StreamingResponseBody> downloadExcel2() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "data.xlsx");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        StreamingResponseBody stream = outputStream -> {
            // 初始化流式工作簿
            try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {
                Sheet sheet = workbook.createSheet("Data Export");

                // 假设你的数据查询方法
                int pageIndex = 0;
                List<TestAppDto> dataBatch;

                // 循环查询数据并写入Excel
                do {
                    dataBatch = fetchDataByPage(pageIndex);

                    int rowStart = sheet.getPhysicalNumberOfRows() + 1; // 获取当前行数
                    for (TestAppDto data : dataBatch) {
                        Row row = sheet.createRow(rowStart++);
                        row.createCell(0).setCellValue(data.getStr());
                        row.createCell(1).setCellValue(data.getSuccess());
                    }
                    pageIndex++;
                } while (!dataBatch.isEmpty()); // 继续查询直到没有更多数据

                // 每次写入后刷新到输出流
                workbook.write(outputStream);
                outputStream.flush(); // 确保数据被发送到客户端
            } catch (IOException e) {
                e.printStackTrace(); // 处理异常
            }
        };

        return new ResponseEntity<>(stream, headers, HttpStatus.OK);
    }


    private List<TestAppDto> fetchDataByPage(int pageIndex) {
        // 模拟从数据库查询分页数据
        List<TestAppDto> list = new ArrayList<>();
        list.add(new TestAppDto().setStr(String.valueOf(pageIndex)).setSuccess(true));
        list.add(new TestAppDto().setStr(String.valueOf(pageIndex + 1)).setSuccess(true));
        list.add(new TestAppDto().setStr(String.valueOf(pageIndex + 2)).setSuccess(true));
        list.add(new TestAppDto().setStr(String.valueOf(pageIndex + 3)).setSuccess(true));

        if (pageIndex == 5) {
            return new ArrayList<>();
        }

        return list;
    }


    @GetMapping("/download")
    public ResponseEntity<StreamingResponseBody> downloadFile() {
        // 假设文件路径
        String filePath = "D:\\下载\\jbhehlbp0uia.zip";

        StreamingResponseBody stream = outputStream -> {
            try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath))) {
                byte[] buffer = new byte[1024]; // 设置缓冲区大小
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    outputStream.flush(); // 确保数据立即写出
                }
            } catch (IOException e) {
                e.printStackTrace();
                // 处理异常
            }
        };

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=jbhehlbp0uia.zip");
        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(stream);
    }


    private final ExecutorService executorService = Executors.newCachedThreadPool();

    @GetMapping("/stream")
    public ResponseEntity<StreamingResponseBody> streamData() {
        // 创建管道输入输出流
        PipedOutputStream outputStream = new PipedOutputStream();
        PipedInputStream inputStream;

        try {
            inputStream = new PipedInputStream(outputStream);

            // 启动线程写入数据
            executorService.submit(() -> {
                try {
                    for (int i = 0; i < 100; i++) {
                        String data = "Data chunk " + i + "\n";
                        log.debug("写入数据.....");
                        outputStream.write(data.getBytes());
                        Thread.sleep(100);
                        outputStream.flush();
                        log.debug("写入完成.....");

                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

            StreamingResponseBody stream = output -> {
                byte[] buffer = new byte[1024];
                int bytesRead;
                try {
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        log.debug("写出数据");
                        output.write(buffer, 0, bytesRead);
                        output.flush();
                        log.debug("写出完成");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    inputStream.close();
                }
            };

            HttpHeaders headers = new HttpHeaders();
//            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=data.txt");
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .body(stream);

        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).build();
        }
    }

    @GetMapping("/download-2")
    public ResponseEntity<StreamingResponseBody> download2() {
        PipedInputStream pipedInputStream = new PipedInputStream();
        PipedOutputStream pipedOutputStream = new PipedOutputStream();

        try {
            // 将输入流和输出流连接
            pipedInputStream.connect(pipedOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 提交任务到线程池来处理 Excel 文件的写入
        executorService.submit(() -> {
            try (Workbook workbook = new XSSFWorkbook(); OutputStream excelOutputStream = pipedOutputStream) {

                // 创建一个工作表
                Sheet sheet = workbook.createSheet("Sheet 1");

                // 模拟数据写入 Excel
                for (int i = 0; i < 1; i++) {
                    Row row = sheet.createRow(i);
                    row.createCell(0).setCellValue("Row " + i);
                }

                // 写入数据到输出流 只要写一次，就算写完成。必须是一次完整的，否则格式有问题
                log.debug("写入数据到输出流");
                workbook.write(excelOutputStream);



            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        // 通过 StreamingResponseBody 将数据流写出到前端
        StreamingResponseBody stream = outputStream -> {
            try {
                // 从 pipedInputStream 读取数据并写入到前端的输出流
                log.debug("写出数据");
                IOUtils.copy(pipedInputStream, outputStream);
                log.debug("copy完成");
            } finally {
                pipedInputStream.close();
            }
        };
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=abc.xlsx");
        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(stream);


    }


}
